// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright @ Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 * Description: euleros populate rootfs
 */
static void __init do_populate_rootfs(void)
{
	/* Load the built in initramfs */
	char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
#ifdef CONFIG_RTOS_BOOT_TIMESTAMP
	get_initrd_start_time();
#endif
	if (err)
		panic("%s", err); /* Failed to decompress INTERNAL initramfs */

	if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE))
		return;

	if (IS_ENABLED(CONFIG_BLK_DEV_RAM))
		pr_info("Trying to unpack rootfs image as initramfs...\n");
	else
		pr_info("Unpacking initramfs...\n");

#ifdef CONFIG_RTOS_MULTI_THREADS_INITRAMFS
	if (is_multi_rootfs((struct multi_rootfs_header *)initrd_start))
		err = multi_threads_unpack_to_rootfs((struct multi_rootfs_header *)initrd_start);
	else
#endif
		err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
	if (err) {
#ifdef CONFIG_BLK_DEV_RAM
		populate_initrd_image(err);
#else
		pr_emerg("Initramfs unpacking failed: %s\n", err);
#endif
	}
}

static void __init do_initrd_free(void)
{
	/*
	 * If the initrd region is overlapped with crashkernel reserved region,
	 * free only memory that is not part of crashkernel region.
	 */
	if (!do_retain_initrd && initrd_start && !kexec_free_initrd())
		free_initrd_mem(initrd_start, initrd_end);
	initrd_start = 0;
	initrd_end = 0;
}

DECLARE_COMPLETION(async_pop_rootfs_done);

static int __init populate_rootfs_async(void *data)
{
	do_populate_rootfs();
	if (!(HOTUPGRADE_WITH(UPGRADE_F_DELAY_INITCALL)))
		do_initrd_free();
	flush_delayed_fput();
#ifdef CONFIG_RTOS_BOOT_TIMESTAMP
	get_initrd_end_time();
#endif
	complete(&async_pop_rootfs_done);
	return 0;
}

static int __init populate_rootfs(void)
{
	struct task_struct *kthread;

	if (!(HOTUPGRADE_WITH(UPGRADE_F_ASYNC_POP_ROOTFS)))
		return populate_rootfs_async(NULL);

	kthread = kthread_run(populate_rootfs_async, NULL, "async_pop_rootfs");
	if (IS_ERR(kthread)) {
		pr_err("cannot start thread to populate rootfs\n");
		return PTR_ERR(kthread);
	}
	return 0;
}
rootfs_initcall(populate_rootfs);

static int populate_rootfs_done(void)
{
	wait_for_completion(&async_pop_rootfs_done);
	return 0;
}
late_initcall_sync(populate_rootfs_done);

static int __init late_free_initrd(void)
{
	/*
	 * kernel_hotupgrade is already 0 when calling this initcall,
	 * use initcall_delaying instead.
	 */
	if (!initcall_delaying)
		return 0;

	do_initrd_free();
	return 0;
}
late_initcall(late_free_initrd);
